﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace cb0tServer
{
    class Captcha
    {
        private static Random rnd = new Random();

        private static String[][] numbers = new String[][]
        {
            new String[]
            {
                "\x000500  \x000501           \x000500  ",
                "\x000500  \x000501   \x000500     \x000501   \x000500  ",
                "\x000500  \x000501   \x000500     \x000501   \x000500  ",
                "\x000500  \x000501   \x000500     \x000501   \x000500  ",
                "\x000500  \x000501           \x000500  "
            },
            new String[]
            {
                "\x000500  \x000501   \x000500  ",
                "\x000500  \x000501   \x000500  ",
                "\x000500  \x000501   \x000500  ",
                "\x000500  \x000501   \x000500  ",
                "\x000500  \x000501   \x000500  "
            },
            new String[]
            {
                "\x000500  \x000501           \x000500  ",
                "\x000500          \x000501   \x000500  ",
                "\x000500  \x000501           \x000500  ",
                "\x000500  \x000501   \x000500          ",
                "\x000500  \x000501           \x000500  "
            },
            new String[]
            {
                "\x000500  \x000501           \x000500  ",
                "\x000500          \x000501   \x000500  ",
                "\x000500  \x000501           \x000500  ",
                "\x000500          \x000501   \x000500  ",
                "\x000500  \x000501           \x000500  "
            },
            new String[]
            {
                "\x000500  \x000501   \x000500          ",
                "\x000500  \x000501   \x000500          ",
                "\x000500  \x000501   \x000500   \x000501   \x000500    ",
                "\x000500  \x000501           \x000500  ",
                "\x000500        \x000501   \x000500    "
            },
            new String[]
            {
                "\x000500  \x000501           \x000500  ",
                "\x000500  \x000501   \x000500          ",
                "\x000500  \x000501           \x000500  ",
                "\x000500          \x000501   \x000500  ",
                "\x000500  \x000501           \x000500  "
            }
        };

        private static String[] plus = new String[]
        {
            "\x000500             ",
            "\x000500     \x000501   \x000500     ",
            "\x000500  \x000501         \x000500  ",
            "\x000500     \x000501   \x000500     ",
            "\x000500             "
        };

        private static String[] minus = new String[]
        {
            "\x000500             ",
            "\x000500             ",
            "\x000500  \x000501         \x000500  ",
            "\x000500             ",
            "\x000500             "
        };

        public static CaptchaObj Create()
        {
            int r = NextNumber(-1);
            int ns = rnd.Next(2, 4);

            List<String> sequence = new List<String>();
            CaptchaObj obj = new CaptchaObj();
            bool should_add = true;

            for (int i = 0; i < ns; i++)
            {
                r = NextNumber(r);
                sequence.Add(r.ToString());

                if (should_add)
                    obj.answer += r;
                else
                    obj.answer -= r;

                if (i < (ns - 1))
                {
                    should_add = (obj.answer < 5);
                    sequence.Add(should_add ? "+" : "-");
                }
            }

            List<byte[]> packets = new List<byte[]>();
            String sample = String.Empty;

            for (int line = 0; line < 5; line++)
            {
                String str = "\x0006";

                foreach (String s in sequence)
                {
                    switch (s)
                    {
                        case "0":
                        case "1":
                        case "2":
                        case "3":
                        case "4":
                        case "5":
                            str += numbers[int.Parse(s)][line];
                            break;

                        case "+":
                            str += plus[line];
                            break;

                        case "-":
                            str += minus[line];
                            break;
                    }
                }

                sample = str;
                packets.Add(ServerOutboundPackets.AnnoucePacket(str));
            }

            int len = (Helpers.StripColors(sample).Length - 1);
            sample = "\x0006\x000500";

            for (int i = 0; i < len; i++)
                sample += " ";

            packets.Insert(0, ServerOutboundPackets.AnnoucePacket(sample));
            packets.Add(ServerOutboundPackets.AnnoucePacket(sample));

            obj.packets = packets.ToArray();
            return obj;
        }

        private static int NextNumber(int last)
        {
            int result = last;

            do
            {
                result = (int)Math.Floor(rnd.NextDouble() * numbers.Length);
            }
            while (result == last);

            return result;
        }

        private static List<Guid> trusted;

        public static void LoadGuids()
        {
            trusted = new List<Guid>();

            try
            {
                String path = sb0t_winGUI.RunOnceFileUpdater.sbotpath + "data/captcha";
                List<byte> buf = new List<byte>(File.ReadAllBytes(path));

                while (buf.Count >= 16)
                {
                    trusted.Add(new Guid(buf.GetRange(0, 16).ToArray()));
                    buf.RemoveRange(0, 16);
                }
            }
            catch { }
        }

        public static void SaveGuids()
        {
            try
            {
                List<byte> buf = new List<byte>();

                foreach (Guid g in trusted)
                    buf.AddRange(g.ToByteArray());

                String path = sb0t_winGUI.RunOnceFileUpdater.sbotpath + "data/captcha";
                File.WriteAllBytes(path, buf.ToArray());
            }
            catch { }
        }

        public static void MakeTrusted(Guid g)
        {
            trusted.Add(g);
        }

        public static bool IsTrusted(Guid g)
        {
            int index = trusted.FindIndex(delegate(Guid g1) { return g1.Equals(g); });

            if (index == -1)
                return false;

            trusted.RemoveAt(index);
            trusted.Add(g);

            if (trusted.Count > 4000)
                trusted.RemoveRange(0, 1000);

            return true;
        }
    }

    class CaptchaObj
    {
        public byte[][] packets = null;
        public int answer = 0;
    }
}
